//! 数据库连接管理模块

use std::collections::HashMap;
use crate::error::{DataForgeError, Result};

/// 数据库连接类型
#[derive(Debug, Clone, PartialEq)]
pub enum DatabaseType {
    MySQL,
    PostgreSQL,
    SQLite,
}

/// 数据库连接配置
#[derive(Debug, Clone)]
pub struct ConnectionConfig {
    pub database_type: DatabaseType,
    pub host: Option<String>,
    pub port: Option<u16>,
    pub database: String,
    pub username: Option<String>,
    pub password: Option<String>,
    pub connection_pool_size: usize,
    pub connection_timeout: u64,
    pub additional_params: HashMap<String, String>,
}

impl ConnectionConfig {
    /// 创建SQLite连接配置
    pub fn sqlite<P: AsRef<str>>(database_path: P) -> Self {
        Self {
            database_type: DatabaseType::SQLite,
            host: None,
            port: None,
            database: database_path.as_ref().to_string(),
            username: None,
            password: None,
            connection_pool_size: 10,
            connection_timeout: 30,
            additional_params: HashMap::new(),
        }
    }

    /// 创建MySQL连接配置
    pub fn mysql<H, D, U, P>(host: H, database: D, username: U, password: P) -> Self
    where
        H: AsRef<str>,
        D: AsRef<str>,
        U: AsRef<str>,
        P: AsRef<str>,
    {
        Self {
            database_type: DatabaseType::MySQL,
            host: Some(host.as_ref().to_string()),
            port: Some(3306),
            database: database.as_ref().to_string(),
            username: Some(username.as_ref().to_string()),
            password: Some(password.as_ref().to_string()),
            connection_pool_size: 10,
            connection_timeout: 30,
            additional_params: HashMap::new(),
        }
    }

    /// 创建PostgreSQL连接配置
    pub fn postgres<H, D, U, P>(host: H, database: D, username: U, password: P) -> Self
    where
        H: AsRef<str>,
        D: AsRef<str>,
        U: AsRef<str>,
        P: AsRef<str>,
    {
        Self {
            database_type: DatabaseType::PostgreSQL,
            host: Some(host.as_ref().to_string()),
            port: Some(5432),
            database: database.as_ref().to_string(),
            username: Some(username.as_ref().to_string()),
            password: Some(password.as_ref().to_string()),
            connection_pool_size: 10,
            connection_timeout: 30,
            additional_params: HashMap::new(),
        }
    }

    /// 设置端口
    pub fn with_port(mut self, port: u16) -> Self {
        self.port = Some(port);
        self
    }

    /// 设置连接池大小
    pub fn with_pool_size(mut self, size: usize) -> Self {
        self.connection_pool_size = size;
        self
    }

    /// 设置连接超时
    pub fn with_timeout(mut self, timeout: u64) -> Self {
        self.connection_timeout = timeout;
        self
    }

    /// 添加额外参数
    pub fn with_param<K, V>(mut self, key: K, value: V) -> Self
    where
        K: AsRef<str>,
        V: AsRef<str>,
    {
        self.additional_params.insert(
            key.as_ref().to_string(),
            value.as_ref().to_string(),
        );
        self
    }

    /// 生成连接字符串
    pub fn to_connection_string(&self) -> Result<String> {
        match self.database_type {
            DatabaseType::SQLite => {
                Ok(format!("sqlite://{}", self.database))
            },
            DatabaseType::MySQL => {
                let host = self.host.as_ref()
                    .ok_or_else(|| DataForgeError::config("MySQL host is required"))?;
                let port = self.port.unwrap_or(3306);
                let username = self.username.as_ref()
                    .ok_or_else(|| DataForgeError::config("MySQL username is required"))?;
                let password = self.password.as_ref()
                    .ok_or_else(|| DataForgeError::config("MySQL password is required"))?;

                let mut conn_str = format!(
                    "mysql://{}:{}@{}:{}/{}",
                    username, password, host, port, self.database
                );

                if !self.additional_params.is_empty() {
                    let params: Vec<String> = self.additional_params
                        .iter()
                        .map(|(k, v)| format!("{}={}", k, v))
                        .collect();
                    conn_str.push('?');
                    conn_str.push_str(&params.join("&"));
                }

                Ok(conn_str)
            },
            DatabaseType::PostgreSQL => {
                let host = self.host.as_ref()
                    .ok_or_else(|| DataForgeError::config("PostgreSQL host is required"))?;
                let port = self.port.unwrap_or(5432);
                let username = self.username.as_ref()
                    .ok_or_else(|| DataForgeError::config("PostgreSQL username is required"))?;
                let password = self.password.as_ref()
                    .ok_or_else(|| DataForgeError::config("PostgreSQL password is required"))?;

                let mut conn_str = format!(
                    "postgresql://{}:{}@{}:{}/{}",
                    username, password, host, port, self.database
                );

                if !self.additional_params.is_empty() {
                    let params: Vec<String> = self.additional_params
                        .iter()
                        .map(|(k, v)| format!("{}={}", k, v))
                        .collect();
                    conn_str.push('?');
                    conn_str.push_str(&params.join("&"));
                }

                Ok(conn_str)
            },
        }
    }

    /// 验证配置
    pub fn validate(&self) -> Result<()> {
        match self.database_type {
            DatabaseType::SQLite => {
                if self.database.is_empty() {
                    return Err(DataForgeError::config("SQLite database path cannot be empty"));
                }
            },
            DatabaseType::MySQL | DatabaseType::PostgreSQL => {
                if self.host.is_none() {
                    return Err(DataForgeError::config("Host is required for MySQL/PostgreSQL"));
                }
                if self.username.is_none() {
                    return Err(DataForgeError::config("Username is required for MySQL/PostgreSQL"));
                }
                if self.password.is_none() {
                    return Err(DataForgeError::config("Password is required for MySQL/PostgreSQL"));
                }
                if self.database.is_empty() {
                    return Err(DataForgeError::config("Database name cannot be empty"));
                }
            },
        }

        if self.connection_pool_size == 0 {
            return Err(DataForgeError::config("Connection pool size must be greater than 0"));
        }

        Ok(())
    }
}

/// 连接管理器
pub struct ConnectionManager {
    config: ConnectionConfig,
    connection_string: String,
}

impl ConnectionManager {
    /// 创建新的连接管理器
    pub fn new(config: ConnectionConfig) -> Result<Self> {
        config.validate()?;
        let connection_string = config.to_connection_string()?;
        
        Ok(Self {
            config,
            connection_string,
        })
    }

    /// 获取连接字符串
    pub fn connection_string(&self) -> &str {
        &self.connection_string
    }
    
    /// 获取连接字符串(返回所有权)
    pub fn get_connection_string(&self) -> Result<String> {
        Ok(self.connection_string.clone())
    }

    /// 获取数据库类型
    pub fn database_type(&self) -> &DatabaseType {
        &self.config.database_type
    }

    /// 获取配置
    pub fn config(&self) -> &ConnectionConfig {
        &self.config
    }

    /// 测试连接
    pub fn test_connection(&self) -> Result<()> {
        // TODO 这里应该实际测试数据库连接,由于我们没有实际的数据库驱动，这里只做配置验证
        self.config.validate()
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_sqlite_config() {
        let config = ConnectionConfig::sqlite("test.db");
        assert_eq!(config.database_type, DatabaseType::SQLite);
        assert_eq!(config.database, "test.db");
        assert!(config.validate().is_ok());
        
        let conn_str = config.to_connection_string().unwrap();
        assert_eq!(conn_str, "sqlite://test.db");
    }

    #[test]
    fn test_mysql_config() {
        let config = ConnectionConfig::mysql("localhost", "testdb", "user", "pass")
            .with_port(3307)
            .with_param("charset", "utf8mb4");
        
        assert_eq!(config.database_type, DatabaseType::MySQL);
        assert_eq!(config.port, Some(3307));
        assert!(config.validate().is_ok());
        
        let conn_str = config.to_connection_string().unwrap();
        assert!(conn_str.contains("mysql://user:pass@localhost:3307/testdb"));
        assert!(conn_str.contains("charset=utf8mb4"));
    }

    #[test]
    fn test_postgres_config() {
        let config = ConnectionConfig::postgres("localhost", "testdb", "user", "pass")
            .with_pool_size(20)
            .with_timeout(60);
        
        assert_eq!(config.database_type, DatabaseType::PostgreSQL);
        assert_eq!(config.connection_pool_size, 20);
        assert_eq!(config.connection_timeout, 60);
        assert!(config.validate().is_ok());
        
        let conn_str = config.to_connection_string().unwrap();
        assert!(conn_str.contains("postgresql://user:pass@localhost:5432/testdb"));
    }

    #[test]
    fn test_connection_manager() {
        let config = ConnectionConfig::sqlite("test.db");
        let manager = ConnectionManager::new(config);
        
        assert!(manager.is_ok());
        let manager = manager.unwrap();
        assert_eq!(manager.connection_string(), "sqlite://test.db");
        assert_eq!(*manager.database_type(), DatabaseType::SQLite);
    }

    #[test]
    fn test_invalid_config() {
        let mut config = ConnectionConfig::mysql("localhost", "testdb", "user", "pass");
        config.connection_pool_size = 0;
        
        assert!(config.validate().is_err());
    }
}